﻿using System;
using System.Collections;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.Security.Principal;
using ActiveDirectoryUtilities.DirectoryServiceAccess;
using Microsoft.SqlServer.Server;
using System.DirectoryServices.Protocols;
using AccessActiveDirectory;

public partial class UserDefinedFunctions
{
	[SqlFunction(FillRowMethodName = "FillDomainControllers", DataAccess = DataAccessKind.Read
		, TableDefinition =
		"DnsHostName NVARCHAR(MAX)"
		+ ", NetBiosName NVARCHAR(MAX)"
		+ ", SiteName NVARCHAR(MAX)"
		+ ", ComputerObjectName NVARCHAR(MAX)"
		+ ", ComputerObjectGuid UNIQUEIDENTIFIER"
		+ ", NtdsDsaObjectName	NVARCHAR(MAX)"
		+ ", NtdsDsaObjectGuid UNIQUEIDENTIFIER"
		+ ", ServerObjectName NVARCHAR(MAX)"
		+ ", ServerObjectGuid UNIQUEIDENTIFIER"
		+ ", SiteObjectName NVARCHAR(MAX)"
		+ ", SiteObjectGuid UNIQUEIDENTIFIER"
		+ ", IsPdc BIT"
		+ ", IsGlobalCatalog BIT"
		+ ", IsDsEnabled BIT"
		)]
	public static IEnumerable fn_FindAllDomainControllers(SqlString domainName)
	{
		EventLogTraceListener eltl = new EventLogTraceListener("Application");
		if (ConfiguredSettings.TraceLevel >= 4)
		{
			Trace.Listeners.Add(eltl);
		}

		WindowsImpersonationContext executionContext = null;
		try
		{
			WindowsIdentity callerId = SqlContext.WindowsIdentity;
			if (callerId != null)
			{
				executionContext = callerId.Impersonate();

				string internalDomainName = string.Empty;
				if (!domainName.IsNull)
				{
					internalDomainName = (string)domainName;
				}

				Domain d;
				try
				{
					if (!string.IsNullOrEmpty(internalDomainName))
					{
						d = Domain.GetDomain(internalDomainName);
					}
					else
					{
						d = Domain.GetCurrentDomain();
					}

					return d.FindAllDomainControllers();
				}
				catch (LdapException ex)
				{
					if (ex.ErrorCode == 81)
					{
						throw new ApplicationException("Could not contact domain:  " + (!string.IsNullOrEmpty(internalDomainName) ? internalDomainName : "Current domain"));
					}
					else
					{
						SharedLogic.LogTraceInfo(eltl, ex, TraceLevel.Error);
						throw ex;
					}
				}
				//catch (Exception ex)
				//{
				//    SharedLogic.LogTraceInfo(eltl, ex, TraceLevel.Error);
				//    throw ex;
				//}

				throw new ApplicationException("Invalid codepath traversed.  Caller should never make it here.");
			}
		}
		finally
		{
			if (Trace.Listeners.Contains(eltl))
			{
				Trace.Listeners.Remove(eltl);
			}
			if (executionContext != null)
			{
				executionContext.Undo();
			}
		}
		return null;
	}

	private static void FillDomainControllers(
		object o
		, out SqlString dnsHostName
		, out SqlString netBiosName
		, out SqlString siteName
		, out SqlString computerObjectName
		, out SqlGuid computerObjectGuid
		, out SqlString ntdsDsaObjectName
		, out SqlGuid ntdsDsaObjectGuid
		, out SqlString serverObjectName
		, out SqlGuid serverObjectGuid
		, out SqlString siteObjectName
		, out SqlGuid siteObjectGuid
		, out SqlBoolean isPdc
		, out SqlBoolean isGlobalCatalog
		, out SqlBoolean isDsEnabled
		)
	{
		DomainController dc = (DomainController)o;
		dnsHostName = dc.DnsHostName;
		netBiosName = dc.NetBiosName;
		siteName = dc.SiteName;
		computerObjectName = dc.ComputerObjectName;
		computerObjectGuid = dc.ComputerObjectGuid;
		ntdsDsaObjectName = dc.NtdsDsaObjectName;
		ntdsDsaObjectGuid = dc.NtdsDsaObjectGuid;
		serverObjectName = dc.ServerObjectName;
		serverObjectGuid = dc.ServerObjectGuid;
		siteObjectName = dc.SiteObjectName;
		siteObjectGuid = dc.SiteObjectGuid;
		isPdc = dc.IsPdc;
		isGlobalCatalog = dc.IsGc;
		isDsEnabled = dc.IsDsEnabled;
	}
};